 //===////////////////////////////////////////////////////////////////////
//                                                                     //
//   PitchDetect V1.13												   //
//                                                                     //
//   Author: Chuan Cao												   //
//	 Base  : V1.12													   //
//   Modify: 06.30.2009  (add an interface and some modification for   //
//						  substitution of the original PitchExactor    //
//                        function of the PitchTracker                 //
//                                                                     //
//   Copyright (c) 2010  ThinkIT Lab., Institute of Acoustic, CAS	   //
//                       All rights reserved                           //
//                                                                     //
//   																   //
//   This class is for detecting pitch of a audio wave if the pitch    //
//   really exists.													   //
//                                                                     //
//																	   //
////////////////////////////////////////////////////////////////////===//

#ifndef PITCHDETECT_H
#define PITCHDETECT_H

#define	PD_ChooseEner	// choose the candidate F0 with biggest saliency
//#define SumOri		// choose the original SHS value instead of the normalized SHS value
//#define Harmn_Saliency_Energy
//#define ACF_Correction	// use the ACF to correct the pitch value in time domain

//#define PD_Use_IPP		//  [11/4/2010 Song]

#include <math.h>
#ifdef PD_Use_IPP
#include <ipps.h>
#else
#include "rsrfft.h"
#endif

enum CheckMode
{
	PEAK,
	VALLEY
};

enum PitchCheckMode
{
	ACF,
	LOW_FREQ_ENER,
	HARM_VS_UNHARM,
	HARMONIC_SALIENCY
};

struct SpecInfo
{
	float	varEn;
	float   energy;
	float	*fft;
	float	*sumHarm_norm;
	float	*sumHarm_ori;
};

struct CandF0
{
	float	F0;
	float	saliency;
};

struct SoundSrcSeg
{
	int		srcID;
	int		startFrame;
	int		length;
	float	*pitch;
	float	*saliency;
};

struct sF0Point 
{
	float F0;
	int	  addTimes;

	float *harmFreq;
	int	  *harmIdx;

	int	  *high, *low;
};

class PitchDetect
{
public:

	PitchDetect();
	PitchDetect(int argc, char *argv[]);
	PitchDetect(char *configFile);
	~PitchDetect();

	int		PitchExtractor(short *waveData, int numSamples, int sampleRate, int **pitch, float **frmEnergy, int **sumHarm, float **varEn);
	float*	PitchExtractor(short *waveData, int numSamples, int sampleRate, int &numFrame);
	
	void	HammingWindow(float *data, int len);
	bool	FFT2PowerSpec(float *fft, int numFFT);
	void	LinearSmoothArray(float *data, int len);
	void	MedianSmoothArray(float *data, int len);

	int		get_Sample_Rate()		{		return _SAMPLE_RATE;	}
	int		get_FFT_Order()			{		return _FFT_ORDER;		}
	int		get_Frame_Len()			{ 		return _Frame_Len;		}
	int		get_Frame_Shift()		{		return _FRAME_SHIFT;	}
	int		get_Frame_Time()		{		return _FRAME_TIME;		}
	int		get_Frame_Shift_Time()	{		return _FRAME_SHIFT_TIME;}

	void	set_Frame_Time(int frameShift){	_FRAME_TIME = frameShift;}								// has bugs in it
	void	set_Frame_Shift_Time(int frameShiftTime){ _FRAME_SHIFT_TIME = frameShiftTime; }
	void	set_Lowest_F0(int f0)	{		_Lowest_F0 = f0;		}
	void	set_Highest_F0(int f0)	{		_Highest_F0 = f0;		}
	void	set_DoSmooth(bool doSmooth)	{	bPos_process = doSmooth;}
	
	virtual bool Initial();

	bool	check_partial(float *fft, int numFFT, float bin_width, float pitch, int partialIdx, int &retBinIdx, float thres);

protected:
	
	virtual void	Default_Setting();

	virtual bool	sample_rate_change();

	virtual void	PitchTracker(short *waveData, int numSamples);

	virtual float	*SoundSrc2Pitch(SoundSrcSeg *SoundSrc, int numSrc);	

	virtual void	SolveCoincidence(SoundSrcSeg &src, int *pitch_srcID, float *pitch, float *saliency);

	// add by mli at 2009-06-30
	int		*chlMap;
	float	*chlWeight;
	float	Mel(int k, float fres) { return (float)(1127.0*log(1.0+(float)k*fres)); }
	void	InitFBank(float lowPass,float highPass);


//private:

	bool	bEnvInit;

	//////////////////////////////////////////////////////////////////////////
	// parameters set
	int	_SAMPLE_RATE, _FRAME_TIME, _FRAME_SHIFT_TIME;
	int	_FFT_ORDER;
	float _varThres;
	
#ifdef PD_Use_IPP
	IppsFFTSpec_R_32f *ipp_spec;
#else
	SplitRadixFFT *fftTool;
#endif

	int	_Lowest_F0, _Highest_F0;
	int	_Max_Harmonics_Freq;

	// window size
	int	_Pitch_Buf_Size, saliency_WinLen;
	
	float _Harmonics_Factor;

	//////////////////////////////////////////////////////////////////////////
	// for SHS
	int _Frame_Len, _FRAME_SHIFT;
	int _Num_FFT;
	int _Max_Harmonics_Num, _NUM_F0;

	float Bin_Width;
	float _Freq_Step;

	float Norm_Factor;

	//////////////////////////////////////////////////////////////////////////
	// for median-filter
	int	_Linear_Smooth_Range, _Median_Smooth_Range;
	
	//////////////////////////////////////////////////////////////////////////
	// for harmonic track process
	int	MaxErrorAllow, shortest_SrcLen;
	int	MaxOnsetNum, MaxHalfSrcLen, MaxSrcNum;

	float CosDistLimit_Track;
	
	//////////////////////////////////////////////////////////////////////////
	// for harmonic structure saliency calculation
	int	MaxCheckIdx, SrchRange_SumHarmn;
	int	MaxLocPkSrchRange;

	int	MaxFrmCand;
	float ConsecutiveLimit_0, CosDistLimit;
	float LocPkSrchRatio;
	
	int SumBins;

	float peak_Thres, peak_Thres_fact;
	float saliency_Thres;

	float *weightSaliency;
	//////////////////////////////////////////////////////////////////////////
	// for patern difference
	bool bCheckPitch;
	bool bHarm_track;
	bool bPos_process;

	char readPitchCheckMode[256];

	PitchCheckMode pitch_check;

	int	stableLen;
	//////////////////////////////////////////////////////////////////////////
	// data area
	int		segIdx, segLen, numSeg;
	int		local_nFrame;
	float	*weightHarm;
	sF0Point *F0Point;
	
	SpecInfo *spec;
	float	*global_pitch;
	float   *pGlb_frmEner;
	int     *pGlb_sumHarm;
	float	*pGlb_varEn;	// add by mli 2009-06-29

	//////////////////////////////////////////////////////////////////////////
	// data buf for global memory malloc, to avoid TOO MUCH memory fragment

	char 	*_pSmpChgBlock;
	char	*_pStaticBlock;

	// pointer to the block

	int		*_pF0PointBufINT;
	float	*_pF0PointBufFLOAT;
	float	*_pHarmWeightBuf;
	float	*_pHammingWinWtBuf;	// add on 2009-10-26

	float	*_pSalWndBuf;
	CandF0	*_pCandF0Buf;
	float	*_pFFTDataBuf;

	SoundSrcSeg *_pSoundSrcBuf;
	

	//////////////////////////////////////////////////////////////////////////


	float	GetDominantPitch(int frameIdx, float *pSumHarm=NULL);

	void	DoSHS();
	
	int		CalcGlobalFFT(short *waveData, int dataLen);

	void	HarmStrucTrack(float *&pitch);

	int		Onset_Detect_CC(float *pitch, int **retOnsetPos);

	int		Offset_Detect_CC(float *pitch, int *onsetPos, int numOnset, SoundSrcSeg **retSoundSrc);

	float	DistConsiderHarmn(float lastPitch, float cand, float *retCand);

	//void	SelectF0(SpecInfo &specInfo, float *retPitch, float *retSumHarmn);

	float	*LocalAcfSaliency(short *waveData, int numSamples, float *pitch, int numPitch);

	void	CheckPitch_ACF(float *pitch, short *waveData, int numSamples);

	void	CheckPitch_LOW_FREQ_ENER(float *pitch);

	void	CheckPitch_HARM_VS_UNHARM(float *pitch);

	void	CheckPitch_HARMONIC_SALIENCY(float *pitch);

	void	CheckPitch_saliency(float *saliency, float *pitch);

	float	Saliency_Window(float checkPitch, int curFrmIdx);
	
//	bool	check_partial(float *fft, float pitch, int partialIdx, int &retBinIdx, float thres);
	
	bool	checkValid(float *fft, int numFFT, float bin_width, float pitch, float *retSaliency);
	
	bool	FindNextPitch(SpecInfo &curSpecInfo, float curPitch,SpecInfo &nextSpecInfo, CandF0 *nextPitch);
	
	int		FindCandF0(SpecInfo &nextSpecInfo, float curPitch, CandF0 *cand);
	
	bool	ChooseF0(CandF0 *cand, int numCand, SpecInfo &curSpecInfo, float curPitch,SpecInfo &nextSpecInfo, CandF0 *nextPitch);
	
	float	CalcHarmnProb(float curPitch, SpecInfo &curSpecInfo, float nextPitch, SpecInfo &nextSpecInfo);

	void	SmpRtChgBlockMemMalloc();

	void	StaticBlockMemMalloc();
	
	template<class Type>
	bool	CheckLocalPeak(Type* serials, int serialLen, int checkIdx, int checkRange, CheckMode mode);
	template<class Type>
	bool	Search_Check(Type* serials, int serialLen, int &checkIdx, int srchRange, int checkRange, CheckMode mode, Type thres);
	
};

#endif